package top.maof.book.rank.book;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;
import top.maof.book.map.BookMap;
import top.maof.book.model.Book;
import top.maof.book.rank.Handle;
import top.maof.book.rank.HandleChain;
import top.maof.book.rank.Rank;
import top.maof.book.rank.RankVo;
import top.maof.book.service.BookService;
import top.maof.book.vo.PageVo;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Component
public class BookHandleRank implements Handle<BookHo>, Rank<Book, BookPage> {

    @Autowired
    private ZSetOperations zSetOperations;

    @Autowired
    private BookService bookService;

    @Autowired
    private BookKeyGenerate bookKeyGenerate;


    private static final String PREFIX_KEY = "rank:book";


    @Override
    public void add(BookHo book, HandleChain handleChain) {
        BookPage bookPage = BookMap.INSTANCE.toBookPage(book);
        bookPage.initTime();
        try {
            Set<String> keys = bookKeyGenerate.generateKeys(bookPage);
            keys.forEach(key -> {
                zSetOperations.incrementScore(HandleChain.generateKey(PREFIX_KEY, book.getHotType().getValue(), key),
                        book.getId(), 1);
            });

        } catch (Exception e) {
            e.printStackTrace();
        }
        handleChain.add(book, handleChain);
    }

    @Override
    public void sub(BookHo book, HandleChain handleChain) {

        BookPage bookPage = BookMap.INSTANCE.toBookPage(book);
        bookPage.initTime();

        try {
            Set<String> keys = bookKeyGenerate.generateKeys(bookPage);
            keys.forEach(key -> {
                zSetOperations.incrementScore(HandleChain.generateKey(PREFIX_KEY, book.getHotType().getValue(), key),
                        book.getId(), -1);
            });

        } catch (Exception e) {
            e.printStackTrace();
        }
        handleChain.sub(book, handleChain);
    }


    @Override
    public PageVo<RankVo<Book>> page(BookPage page) {
        String key = null;
        try {
            key = HandleChain.generateKey(PREFIX_KEY, page.getHotType().getValue(), bookKeyGenerate.generateKey(page));
            Set<ZSetOperations.TypedTuple<Integer>> set = null;
            if (page.getIsAsc() != null && page.getIsAsc()) {
                set = zSetOperations.rangeWithScores(key, (page.getPage() - 1) * page.getPageSize(),
                        page.getPage() * page.getPageSize() - 1);
            } else {
                set = zSetOperations.reverseRangeWithScores(key, (page.getPage() - 1) * page.getPageSize(),
                        page.getPage() * page.getPageSize() - 1);
            }
            Long size = zSetOperations.size(key);
            List<RankVo<Book>> list = new ArrayList<>(set.size());
            set.forEach(tuple -> {
                Integer bookId = tuple.getValue();
                RankVo rankVo = new RankVo();
                rankVo.setScore(tuple.getScore());
                rankVo.setT(bookService.find(bookId));
                list.add(rankVo);
            });
            PageVo pageVo = new PageVo();
            pageVo.setCount(size);
            pageVo.setList(list);
            return pageVo;

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

}
